iT邦幫忙

2022 iThome 鐵人賽

DAY 6
0
自我挑戰組

JavaScript 30天挑戰 自學筆記系列 第 6

JS30 自學筆記 Day06_Ajax Type Ahead

  • 分享至 

  • xImage
  •  

今日任務: 輸入關鍵字後,顯示所有與關鍵字相關的城市或景點

作者有給我們資料網址

const endpoint ='https://gist.githubusercontent.com/Miserlou/c5cd8364bf9b2420bb29/raw/2bf258763cdddd704f8ffd3ea9a3e81d25e2c6f6/cities.json'

使用 Fetch 發送請求 ( request )

這裡要使用 fetch 透過網路取得 json 然後印出在 console,最簡單的方式只需要一個參數就是資料的 URI,fetch 會回傳一個包含 response 的 promise 。

1. 獲取api

fetch(endpoint).then(function (response) {
    console.log(response)
})

2.再將它轉成json檔使用

fetch(endpoint).then((response) => {
    return response.json()
})

它會return資料,可以再繼續下一個.then使用

fetch(endpoint)
    .then((response) => {
        return response.json()
    })
    .then((data) => {
        console.log(data)
})

將資料放進我們的cities陣列裡面(順便將函式簡寫)

let cities = []
fetch(endpoint)
    .then((response) => response.json())
    .then((data) => (cities = data))

如果你不想更改你的cities陣列,也可以用push

let cities = []
fetch(endpoint)
    .then((response) => response.json())
    .then((data) => cities.push(...data))

正規表達式(regular expressions)

RegExp 物件被用來比對符合自訂規則的文字。
new RegExp("pattern", "flag")
撰寫正規表達式時,使用兩個斜線 / / 或是 new RegExp() 來建立一個 RegExp 物件。
第一個參數放要搜尋的規律或內容
第二個參數放比對的方式

  • g:全域比對(Global match)
  • i:忽略大小寫(Ignore case)

這邊放上詳細介紹

使用 String.prototype.match(regexp) 這個方法來判斷給的字串當中是否有符合該 regexp pattern 的內容,有的話以陣列回傳,沒有的話回傳 null。

比對city和state兩種

function findMatches(wordToMarch, cities) {
    return cities.filter((place) => {
        //找出和關鍵字相符合的城市或景點
        const regex = new RegExp(wordToMarch, 'gi')
        return place.city.match(regex) || place.state.match(regex)
    })
}

監聽文字輸入框

const searchInput = document.querySelector('.search')

searchInput.addEventListener('keyup', rederMatches)
searchInput.addEventListener('change', rederMatches)

function rederMatches() {
    console.log(this.value)
}

將文字內容進行比對

function rederMatches() {
    const matchArray = findMatches(this.value, cities)
    console.log(matchArray)
}

將得到的結果陣列.map()跑一遍,最後渲染到html

const suggestions = document.querySelector('.suggestions')
function rederMatches() {
    const matchArray = findMatches(this.value, cities)
    console.log(matchArray)
    const html = matchArray.map((place) => {
    return `
    <li>
       <span class="name">${place.city}, ${place.state}</span>
       <span class="population">${place.population}</span>
    </li>`
    })
    suggestions.innerHTML = html
}

畫面上會出現逗號

Array.prototype.join()

會將陣列(或一個類陣列(array-like)物件)中所有的元素連接、合併成一個字串,並回傳此字串。

function rederMatches() {
    const matchArray = findMatches(this.value, cities)
    console.log(matchArray)
    const html = matchArray.map((place) => {
    return `
    <li>
       <span class="name">${place.city}, ${place.state}</span>
       <span class="population">${place.population}</span>
    </li>`
    }).join('')
    suggestions.innerHTML = html
}

將關鍵字highlight出來

String.prototype.replace(pattern, replacement)

  • replace() 方法會傳回一個新字串,此新字串是透過將原字串與 pattern 比對,以 replacement 取代吻合處而生成。pattern可以是字串或 RegExp,而 replacement 可以是字串或函式(會在每一次匹配時被呼叫)。
  • 這個方法會回傳置換後的新字串,不會改變原本的字串
//關鍵字
const regex = new RegExp(this.value, 'gi')
//將關鍵字highlight出來
const cityName = place.city.replace(regex, `<span class="highlight">${this.value}</span>`)
console.log(cityName)

function rederMatches() {
    const matchArray = findMatches(this.value, cities)
    const html = matchArray.map((place) => {
        //關鍵字
        const regex = new RegExp(this.value, 'gi')
        //將關鍵字highlight出來
        const cityName = place.city.replace(regex, `<span class="highlight">${this.value}</span>`)
        const stateName = place.state.replace(regex, `<span class="highlight">${this.value}</span>`)
        return `
            <li>
                <span class="name">${cityName}, ${stateName}</span>
                <span class="population">${place.population}</span>
            </li>`
    }).join('')
                
    suggestions.innerHTML = html
}

人口數每三個數字加上逗號

\B(?=(\d{3})+(?!\d))是作者直接貼上的正規表達式
參考
十五分鐘認識正規表達式,解決所有文字難題
將數字加上 comma 的正規表達式說明

\B 比對非文字邊界,包括空格及特別字元。
A(?=B) → A 後方的條件要符合 B
\d 比對一個數字,相等於 /[0-9]/
A(?!B) → A 後方的條件不能符合 B

所以\B(?=(\d{3})+(?!\d))可拆解為
\d{3} =\d\d\d,比對 3 個連續的數字
(\d{3})+ 代表匹配一次或多次連續 3 個數字
\B(?=(\d{3})+
非文字邊界(下圖藍線)後要匹配一次或多次連續 3 個數字(紅色箭頭為藍線3個一數)
(?!\d)後方不能再有數字

function numberWithCommas(x) {
  return x.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ',');
}

放到我們的渲染函式中

return 
`<li>
   <span class="name">${cityName}, ${stateName}</span>
   <span class="population">${numberWithCommas(place.population)}</span>
</li>`

今日學習到的:

  • 使用 Fetch 發送請求 ( request )
  • 正規表達式(regular expressions)
  • Array.prototype.join()
  • String.prototype.replace(pattern, replacement)

效果連結:連結

參考連結:
MDN: Fetch
MDN: RegExp
String.prototype.match()
正規表示法(Regular expressions)
pjchender: 正則表達式
MDN: join()
MDN: replace()
正規表達式(RegExp)
十五分鐘認識正規表達式,解決所有文字難題
將數字加上 comma 的正規表達式說明


上一篇
JS30 自學筆記 Day05_Flex Panels Image Gallery
下一篇
JS30 自學筆記 Day07_Array Cardio Day 2
系列文
JavaScript 30天挑戰 自學筆記30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言